﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using PE2470_Auswertung.Properties;
using System.IO;
using System.IO.Ports;
using System.Threading;
using ZedGraph;

namespace PE2470_Auswertung
{
    #region Public Enumeration
    public enum DataMode {Text, Hex }
    public enum LogMsyType {Incoming, Outgoing, Normal, Warning, Error};
    #endregion

    public partial class Main : Form
    {
        #region Local Variables
            // The main controll for communicationg throught the RS232 Port
        private SerialPort comport = new SerialPort();
            // Various colors for logging info
        private Color[] LogMsgTypeColor = { Color.Blue, Color.Green, Color.Black, Color.Orange, Color.Red };
            // Temp holder for whether a key was pressed
        //private bool KeyHandled = false;
            // App Settings
        private Settings  settings = Settings.Default;
            // Curve Points
        private int[] CurvePoint = new int[16];
        private int[] DemoPoint  = new int[16];
            // ProgressBar 
        //private int Progress = 0;
            // Nulldurchgangs Interpolation EIN/AUS
        private bool IntPol_On = false;
        private bool Demo_On = false;
            // Nulldurchgangshilfvariablen
        int min = 0, max = 0, zero = 0, IndGrößer = 0, IndKleiner = 0, amplitude = 0, d = 0, FpgaPos = 0, xPos;
        double k = 0.0, relPos = 0.0, FpgaAbsCount = 0.0;  //xPos = 0.0,

        #endregion

        #region Local Properties
        private DataMode CurrentDataMode
        {
            get
            {
                if (rdbDataHex.Checked) return DataMode.Hex;
                else return DataMode.Text;
            }
            set
            {
                if (value == DataMode.Text) rdbDataText.Checked = true;
                else rdbDataHex.Checked = true;
            }
        }
        #endregion
        
        #region Constructor
        public Main()
        {
            // Load user Settings
            settings.Reload();
            
            // Build the form
            InitializeComponent();

            // Restore the user settings
            InitializeControlValues(); 

            // Enable/Disable controls base on the current COM-Port state
            EnableControls();

            // When data is reveived through the port, call this method
            comport.DataReceived += new SerialDataReceivedEventHandler(comport_DataReceived);
            
            // When pins are chanched, call this method
            comport.PinChanged += new SerialPinChangedEventHandler(comport_PinChanged);

            // CreateGraphic
            CreatePlot(zdPlot);

            // Demopoints
            DemoPoint[1] = 718;
            DemoPoint[2] = 626;
            DemoPoint[3] = 428;
            DemoPoint[4] = 205;
            DemoPoint[5] = 72;
            DemoPoint[6] = 124;
            DemoPoint[7] = 265;
            DemoPoint[8] = 433;
            DemoPoint[9] = 634;
            DemoPoint[10] = 740;
            DemoPoint[11] = 718;
            DemoPoint[12] = 626;
            DemoPoint[13] = 428;
            DemoPoint[14] = 205;
            DemoPoint[15] = 72;
        }
        #endregion

        void comport_PinChanged(object sender, SerialPinChangedEventArgs e)
        {
            //Show the state of the pins
            UpdatePinState();
        }

        private void CreatePlot(ZedGraphControl zdPlot)
        {
            GraphPane myPane = zdPlot.GraphPane;

            // Set the titles and acis labels
            myPane.Title.Text = "Sinus Signal";
            myPane.XAxis.Title.Text = "Pulse";
            myPane.YAxis.Title.Text = "Time in [ns]";
            
            // Make up some data point form the sine function
            PointPairList list = new PointPairList();

            //for (double x = 0; x < 10; x++)
            //{
            //    double y = Math.Sin(3*x * Math.PI / 5.0 + Phasenverschiebung);
            //    list.Add(x, y);
            //}
            // Punkte[1 - 10]
            //

            // Expand CurvePoints
            for (int d = 1; d <= 5; d++)
            {
                CurvePoint[d + 10] = CurvePoint[d];
            }


            // Erweiterte Punkte anzeigen von 1397 - 1905 [11 - 15]
            int i;
            if (IntPol_On)
            {
                i = 1;
                for (int x = 127; x <= 1905; x+=127)
                {
                    int y = CurvePoint[i];
                    list.Add(x, y);
                    i++;
                }
                // Nulldurchgang berechnen
                CalcZeroPoint(CurvePoint);
            }
            else
            {
                i = 1;
                for (int x = 127; x <= 1270; x += 127)
                {
                    int y = CurvePoint[i];
                    list.Add(x, y);
                    i++;
                }
            } //end IF Interpolation 

            // Clean all curvs
            zdPlot.GraphPane.CurveList.Clear();

            // Generate a blue curve
            LineItem myCurve = myPane.AddCurve("My Curve", list, Color.Blue);

            // Generate a horizontal line
            PointPairList HLine = new PointPairList();
            for (int x = 0; x < 2032; x+=127)
            {
                HLine.Add(x, zero);
            }
            myCurve = myPane.AddCurve("HLine", HLine, Color.DarkGreen);

            // Generate a tangent line
            PointPairList TLine = new PointPairList();
            for (int x = 0; x < 2032; x += 127)
            {
                TLine.Add( x, k*x+d);
            }
            myCurve = myPane.AddCurve("TLine", TLine, Color.Red);

            // Calculate Y Axis
            myPane.YAxis.Scale.Max = 1000;
            myPane.YAxis.Scale.Min = 0;
            //myPane.Fill.

            // Calculate X Axis
            myPane.XAxis.Scale.Min = 0;
            myPane.XAxis.Scale.Max = 2032;
            myPane.XAxis.Scale.MajorStep = 127;
            myPane.XAxis.Scale.MinorStep = 127;


            // Calculate the Axis Scale Range
            zdPlot.AxisChange();

            zdPlot.Refresh();
        }

        private void CalcZeroPoint(int[] CurvePoint)
        {
            //int min = 0, max = 0, zero = 0, größer = 0, kleiner = 0, amplitude = 0;
            int tempSteigung;
            max = 0;
            min = 1000;
            // Größten Wert finden
            for (int i = 0; i < 10; i++)
            {
              if (max < CurvePoint[i]) max = CurvePoint[i];
              if (min > CurvePoint[i]) min = CurvePoint[i];
            }
            // Mittelwert
            amplitude = max - min;
            //zero = min + (amplitude / 2);

            int mytemp = 0;
            for (int i = 1; i <= 10; i++)
            {
                mytemp += CurvePoint[i];
            }
            zero = mytemp / 10;


            // Festlegung auf Nulldurchgang bei steigender Flanke
            // Suche zuerst negativen Wert dannach den ersten positiven wert. 
            // Index -1 bei ersten positiven Wert ergibt Nulldurchgang 
            // Nähester Wert unter dem Mittelwert
            IndGrößer = 1;
            while (IndGrößer <= 10 && CurvePoint[IndGrößer] >= zero) IndGrößer++;
            while (IndGrößer <= 10 && CurvePoint[IndGrößer] < zero) IndGrößer++;        // Nähester Wert über den Mittelwert
            IndKleiner = IndGrößer - 1;

                           tempSteigung = (CurvePoint[IndGrößer] - CurvePoint[IndKleiner]);
                           // // Verschiebung d ausrechnen
                            d = ((tempSteigung * IndKleiner) - CurvePoint[IndKleiner])*-1;

                           // // Steigung k ausrechnen
                            k = tempSteigung / 127.0;

                           // // Position ausrechnen
                           // // x=(y-d)/k
                           // xPos = ((zero - d) / k);

            // a ausrechnen mittels Formel a= (127x)/(x+y)
            if ((CurvePoint[IndGrößer] - CurvePoint[IndKleiner])!= 0)
            {
                xPos = 127 * (zero - CurvePoint[IndKleiner]) / (CurvePoint[IndGrößer] - CurvePoint[IndKleiner]);
                xPos = xPos + (IndKleiner * 127);                                
            }

            // DeltaPosition ausrechnen



            // Relative Position ausrechnen
            relPos = Math.Round( xPos * 0.0005,3);

        }
       
        private void UpdatePinState()
        {
            this.Invoke(new ThreadStart(() =>
            {
                //Show the state of the pins
                chbDSR.Checked = comport.DsrHolding;
                chbCTS.Checked = comport.CtsHolding;
                chbCD.Checked = comport.CDHolding;
            }));
        }

        private void InitializeControlValues()
        {
            cmbParity.Items.Clear();    cmbParity.Items.AddRange(Enum.GetNames(typeof(Parity)));
            cmbStopBits.Items.Clear(); cmbStopBits.Items.AddRange(Enum.GetNames(typeof(StopBits)));

            cmbParity.Text = settings.Parity.ToString();
            cmbStopBits.Text = settings.StopBits.ToString();
            cmbDataBits.Text = settings.DataBits.ToString();
            cmbParity.Text = settings.Parity.ToString();
            cmbBaud.Text = settings.BaudRate.ToString();

            CurrentDataMode = settings.DataMode;

            RefreshComPortList();
           
            // Erweiterung
            //chkClearOnOpen.Checked = settings.ClearOnOpen;
            //chkClearWithDTR.Checked = settings.ClearWithDTR;

            // If it is still avalible, select the last com port used
            if (cmbPortName.Items.Contains(settings.PortName)) cmbPortName.Text = settings.PortName;
            else if (cmbPortName.Items.Count > 0) cmbPortName.SelectedIndex = cmbPortName.Items.Count - 1;
            else
	        {
                MessageBox.Show(this, "There are no COM-Ports available on this computer. \nPlease install a COM-Port and restart the app.", "No COM Port Installed", MessageBoxButtons.OK, MessageBoxIcon.Error);
                //this.Close();
            }
        }

        private void RefreshComPortList()
        {
            //// Determain if the list of com port anmes has changed since last checked
            //string selected = RefreshComPortList(cmbPortName.Items.Cast<string>(), cmbPortName.SelectedItem as string, comport.IsOpen);

            //// If there was an update, then update the control showing the user the list of port names
            //if (!String.IsNullOrEmpty(selected))
            //{
            cmbPortName.Items.Clear();
            cmbPortName.Items.AddRange(OrderedPortNames());
            //    cmbPortName.SelectedItem = selected;
            //}
        }

        private object[] OrderedPortNames()
        {
           //Just a placeholder for a successful parsing of a string to an interger
            int num;
            // Order the serial port names in numeric order (if possible)
            return SerialPort.GetPortNames().OrderBy(a => a.Length > 3 && int.TryParse(a.Substring(3), out num) ? num : 0).ToArray();
        }      

        private void EnableControls()
        {
            // Enable/disable controls based on whether the port is open or not
            gbPortSettings.Enabled = !comport.IsOpen;
            gbSend.Enabled = comport.IsOpen;
            //gbLog.Enabled = comport.IsOpen;

            if (comport.IsOpen) btnOpenPort.Text = "&Close Port";
            else btnOpenPort.Text = "&Open Port";
        }

        #region Event Handler

        private void btngIntPol_Click(object sender, EventArgs e)
        {
            if (IntPol_On)
            {
                IntPol_On = false;
                btngIntPol.Text = "ON";
            }
            else
            {
                IntPol_On = true;
                btngIntPol.Text = "OFF";
            }
        }
        
        private void btDemo_Click(object sender, EventArgs e)
        {
            if (Demo_On)
            {
                Demo_On = false;
                btDemo.Text = "ON";
            }
            else
            {
                Demo_On = true;
                btDemo.Text = "OFF";
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            // The Form is closing, save the user's preferences
            SaveSettings();
        }

        private void rdbDataText_CheckedChanged(object sender, EventArgs e)
        { if (rdbDataText.Checked) CurrentDataMode = DataMode.Text; }

        private void rdbDataHex_CheckedChanged(object sender, EventArgs e)
        { if (rdbDataHex.Checked) CurrentDataMode = DataMode.Hex; }

        private void btnOpenPort_Click(object sender, EventArgs e)
        {
            bool error = false;

            // IF the port is open, close it.
            if (comport.IsOpen)
            {
                try
                {
                    comport.Close();
                    stlStatus.Text = "Disconnected";
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.ToString(), "Error closing Port", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    this.Close();
                }

            }
            else
            {
                // Set the port's settings
                comport.BaudRate = int.Parse(cmbBaud.Text);
                comport.DataBits = int.Parse(cmbDataBits.Text);
                comport.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cmbStopBits.Text);
                comport.Parity = (Parity)Enum.Parse(typeof(Parity), cmbParity.Text);
                comport.PortName = cmbPortName.Text;

                comport.NewLine = "\r\n";
                comport.ReceivedBytesThreshold = 28; //24
                Log(LogMsyType.Normal, "BytesThreshold: "+ comport.ReceivedBytesThreshold.ToString()+" End");

                try
                {
                    // Open the port
                    comport.Open();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(this, "Could not open the COM port.  \nMost likely it is already in use, has been removed, or is unavailable.\n" + ex.ToString(), "COM Port Unavalible", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    stlStatus.Text = "Error";
                    error = true;
                }

                if (!error)
                {
                    //Show the inital pin states
                    UpdatePinState();
                    stlStatus.Text = "Connected";
                }
            }
            // Change the state of the port controls
            EnableControls();

            // Change the state of the form's controls
            if (comport.IsOpen)
            {
                txbSend.Focus();
            }

        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (CurrentDataMode == DataMode.Text){
                //Send the user text straight out the port
                comport.Write(txbSend.Text);

                //Show in the terminal window the user text
                Log(LogMsyType.Outgoing, txbSend.Text + "\n");
            }
            else {
                try
                {
                    //Convert the user string of hex digits (like: E2 AB 1F) to a byte array
                    byte[] data = HexStringToByteArray(txbSend.Text);

                    // Send the binary data out the port
                    comport.Write(data, 0, data.Length);

                    //Show the hex digits on the terminal window
                    Log(LogMsyType.Outgoing, ByteArrayToHexString(data) + "\n");
                }
                catch (Exception)
                {
                    // Inform the user if the hex string was not properly formatted
                    Log(LogMsyType.Error, "Not properly formatted hex string: " + txbSend.Text +"\n");
                }
            }
            txbSend.SelectAll(); //??
        }
        
        void comport_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // If the com port has been closed, do nothing
            if (!comport.IsOpen) return;

            // This method will be called when there is data waiting in the port´s buffer

            //Determain witch mode (string or binary) the user is in
            if (CurrentDataMode == DataMode.Text)
            {
                //Read all the data waiting in the buffer
                //string data = comport.ReadExisting();

                string data = comport.ReadLine(); 
                
                // Display the text to the user in the terminal
                Log(LogMsyType.Incoming, data + " Received: " + data.Length.ToString() + "\n");
                
                // Daten in Byte array umwandeln
                byte[] buffer = new byte[data.Length];
                
                for (int i = 0; i < data.Length; i++)
                {
                    buffer[i] = Convert.ToByte(data[i]);
                }

                //// Übertragung correct
                //if (buffer.Length == 22)
                //{
                //    int buffoffset = 0;
                //    for (int i = 0; i < CurvePoint.Length; i++)
                //    {
                //        CurvePoint[i] = BitConverter.ToInt16(buffer, buffoffset);
                //        buffoffset += 2;
                //    }

                //    UpdateDataBoxes();

                //    // Progress Bar
                //    //if (ProgressBar.Value < 100) Progress                       
                //    //else ProgressBar.Value = 0;

                //    //ProgressBar.Value = Progress;

                //    //Console.WriteLine(Progress);
                //}
                //else
                //{
                //    Log(LogMsyType.Error, "Not correkt received: " + data.Length.ToString() + "Bytes\n");
                //    comport.DiscardInBuffer();
                //}


            }
            else
            {
                // Obtain the number of bytes waiting in the port buffer
                int bytes = comport.BytesToRead;

                // Create a byte array buffer to hold the incoming data
                byte[] buffer = new byte[bytes];

                // Read the data from the port and store it in our buffer
                comport.Read(buffer, 0, bytes);

                // Show the user the incoming data in hex format
                Log(LogMsyType.Incoming, ByteArrayToHexString(buffer)+" Received: "+bytes.ToString()+"\n");

                // Übertragung correct
                if (buffer.Length == 28 && buffer[26]=='\r'&&buffer[27]=='\n')
                {
                    int buffoffset = 0;

                    for (int i = 1; i <= 10 ; i++)
                    {
                        //CurvePoint[i] = BitConverter.ToInt16(buffer, buffoffset);
                        CurvePoint[i] = BitConverter.ToUInt16(buffer, buffoffset);
                        buffoffset += 2;
                    }

                    FpgaPos = BitConverter.ToUInt16(buffer, 20);
                    FpgaAbsCount = BitConverter.ToInt32(buffer, 22);

                    //// Expand CurvePoints
                    //for (int d = 1; d <= 5; d++)
                    //{
                    //    CurvePoint[d + 10] = CurvePoint[d];
                    //}
                    
                    UpdateDataBoxes();

                }
                else
                {
                    Log(LogMsyType.Error, "Not correkt received: " + buffer.Length.ToString() + "Bytes\n");
                    comport.DiscardInBuffer();   
                }
            }


        }
        
        /// <summary>
        /// Plot aktualisieren
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            // Demo
            if (Demo_On)
	        {
                for (int i = 1; i <= 10; i++)
                {
                    CurvePoint[i] = DemoPoint[i]; 
                }
                UpdateDataBoxes(); 
	        }
            
            
            CreatePlot(zdPlot);
        }

        /// <summary>
        ///  Demowerte versetzten und durchschieben
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            int temp = DemoPoint[1];
            for (int i = 1; i <= 9; i++)
            {
                DemoPoint[i] = DemoPoint[i+1];             
            }
            DemoPoint[10] = temp;
        }
       
        #endregion

        #region Local Methods

        /// <summary> Log data to the terminal windows. </summary>
        /// <param name="msgtype"> The type of message to be written. </param>
        /// <param name="msg"> The string containing the message to be shown. </param>
        private void Log(LogMsyType msgtype, string msg)
        {
            rtbLog.Invoke(new EventHandler(delegate
            {
                rtbLog.SelectedText = string.Empty;
                rtbLog.SelectionFont = new Font(rtbLog.SelectionFont, FontStyle.Bold);
                rtbLog.SelectionColor = LogMsgTypeColor[(int)msgtype];
                rtbLog.AppendText(msg);
                rtbLog.ScrollToCaret();
            }));
        }

        /// <summary> Convert a string of hex digits (like: E4 CA B2) to a byte array.</summary>
        /// <param name="s"> The string containing the hex digits (with or without spaces).</param>
        /// <returns> Returns an array of bytes. </returns>
        private Byte[] HexStringToByteArray(string s)
        {
            s = s.Replace(" ", "");
            byte[] buffer = new byte[s.Length/2];
            for (int i = 0; i < s.Length; i += 2)
                buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
            return buffer;
        }

        /// <summary> Convert an array of bytes into formatted string of hex digits (like: E4 CA B2) </summary>
        /// <param name="data">The array of bytes to be translated into a sting of hex digits.</param>
        /// <returns>Returns a formatetted string of hex digits with spacing.</returns>
        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
            return sb.ToString().ToUpper();
        }

        /// <summary> Save the user settings </summary>
        private void SaveSettings()
        {
            settings.DataMode  = CurrentDataMode;
            settings.BaudRate = int.Parse(cmbBaud.Text);
            settings.DataBits = int.Parse(cmbDataBits.Text);
            settings.Parity   = (Parity)Enum.Parse(typeof(Parity), cmbParity.Text);
            settings.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cmbStopBits.Text);
            settings.PortName = cmbPortName.Text;

            settings.Save();
        }

        /// <summary> Update the Curve Data. </summary>
        private void UpdateDataBoxes()
        {
            txbData1.Invoke(new EventHandler(delegate
            {
                txbData1.Text = CurvePoint[1].ToString();
                txbData2.Text = CurvePoint[2].ToString();
                txbData3.Text = CurvePoint[3].ToString();
                txbData4.Text = CurvePoint[4].ToString();
                txbData5.Text = CurvePoint[5].ToString();
                txbData6.Text = CurvePoint[6].ToString();
                txbData7.Text = CurvePoint[7].ToString();
                txbData8.Text = CurvePoint[8].ToString();
                txbData9.Text = CurvePoint[9].ToString();
                txbData10.Text = CurvePoint[10].ToString();
                txbAmplitude.Text = amplitude.ToString();
                txbZeroLine.Text = zero.ToString();
                txbGrößer.Text = IndGrößer.ToString();
                txbKleiner.Text = IndKleiner.ToString();
                txbK.Text = k.ToString();
                txbD.Text = d.ToString();
                txbxPos.Text = xPos.ToString();
                txbRelPos.Text = relPos.ToString() + "mm";
                txbFpgaPos.Text = FpgaPos.ToString();
                txbAbsCnt.Text = (Math.Round(FpgaAbsCount * 0.0005, 3)).ToString() + "mm";
            }));
            //txbData2.Invoke(new EventHandler(delegate
            //{
            //    txbData2.Text = CurvePoint[2].ToString();
            //}));
            //txbData3.Invoke(new EventHandler(delegate
            //{
            //    txbData3.Text = CurvePoint[3].ToString();
            //}));
            //txbData4.Invoke(new EventHandler(delegate
            //{
            //    txbData4.Text = CurvePoint[4].ToString();
            //}));
            //txbData5.Invoke(new EventHandler(delegate
            //{
            //    txbData5.Text = CurvePoint[5].ToString();
            //}));
            //txbData6.Invoke(new EventHandler(delegate
            //{
            //    txbData6.Text = CurvePoint[6].ToString();
            //}));
            //txbData7.Invoke(new EventHandler(delegate
            //{
            //    txbData7.Text = CurvePoint[7].ToString();
            //}));
            //txbData8.Invoke(new EventHandler(delegate
            //{
            //    txbData8.Text = CurvePoint[8].ToString();
            //}));
            //txbData9.Invoke(new EventHandler(delegate
            //{
            //    txbData9.Text = CurvePoint[9].ToString();
            //}));
            //txbData10.Invoke(new EventHandler(delegate
            //{
            //    txbData10.Text = CurvePoint[10].ToString();
            //}));
            //txbAmplitude.Invoke(new EventHandler(delegate
            //{
            //    txbAmplitude.Text = amplitude.ToString();
            //}));
            //txbZeroLine.Invoke(new EventHandler(delegate
            //{
            //    txbZeroLine.Text = zero.ToString();
            //}));
            //txbGrößer.Invoke(new EventHandler(delegate
            //{
            //    txbGrößer.Text = IndGrößer.ToString();
            //}));
            //txbKleiner.Invoke(new EventHandler(delegate
            //{
            //    txbKleiner.Text = IndKleiner.ToString();
            //}));
            //txbK.Invoke(new EventHandler(delegate
            //{
            //    txbK.Text = k.ToString();
            //}));
            //txbD.Invoke(new EventHandler(delegate
            //{
            //    txbD.Text = d.ToString();
            //}));
            //txbxPos.Invoke(new EventHandler(delegate
            //{
            //    txbxPos.Text = xPos.ToString();
            //}));
            //txbRelPos.Invoke(new EventHandler(delegate
            //{
            //    txbRelPos.Text = relPos.ToString() + "mm";
            //}));
            //txbFpgaPos.Invoke(new EventHandler(delegate
            //{
            //    txbFpgaPos.Text = FpgaPos.ToString();
            //}));
            //txbAbsCnt.Invoke(new EventHandler(delegate
            //{
            //    txbAbsCnt.Text = (Math.Round(FpgaAbsCount*0.0005,3)).ToString()+"mm";
            //}));
        }
        #endregion



    }//End Class
}
